package net.gdface.json;

import java.util.Calendar;
import java.util.Date;

import com.google.common.primitives.Primitives;

import net.gdface.utils.BaseTypeTransformer;
import net.gdface.utils.DateSupport;

/**
 * JSON序列化/反序列化支持抽象类
 * @author guyadong
 * @since 2.7.0
 */
public abstract class JsonSupport {
	private static final BaseTypeTransformer TRANSFORMER = new BaseTypeTransformer();

	/**
	 *  对象序列化为JSON字符串[无缩进]
	 * @param object
	 */
	public String toJSONString(Object object){
		return toJSONString(object,false);
	}
	/**
	 * 对象序列化为JSON字符串
	 * @param object
	 * @param prettyFormat 为{@code true}输出缩进的格式化字符串
	 * @throws JsonSupportException JSON序列化异常
	 */
	public abstract String toJSONString(Object object, boolean prettyFormat) throws JsonSupportException;
	/**
	 * 解决JSON字符串为JSON对象，字符串为空或{@code null}则返回空对象(Map)
	 * @param json
	 * @param throwOnfail 为{@code true}时解析抛出异常,否则解析失败则返回原始JSON字符串
	 * @throws JsonSupportException SON序列化异常,{@code throwOnfail}为{@code true}时抛出
	 * @since 2.7.2
	 */
	public Object parseOrEmptyMap(String json,boolean throwOnfail) throws JsonSupportException{
		try {
			return parseOrEmptyMap(json);
		} catch (RuntimeException e) {
			if(!throwOnfail){
				// 解析失败则忽略返回原始值
				return json;
			}
			throw e;
		}
	}
	/**
	 * 解决JSON字符串为JSON对象，字符串为空或{@code null}则返回空对象(Map)
	 * @param json
	 * @throws JsonSupportException JSON解析异常
	 */
	public abstract Object parseOrEmptyMap(String json) throws JsonSupportException;
	/**
	 * 解析JSON字符串为指定的类型的对象，字符串为空或{@code null}则返回{@code null}
	 * @param json
	 * @param targetType
	 * @throws JsonSupportException JSON解析异常
	 */
	protected abstract <T>T doParse(String json,Class<T> targetType) throws JsonSupportException;
	/**
	 * 解析JSON字符串为指定的类型的对象，字符串为空或{@code null}则返回{@code null}
	 * @param json
	 * @param targetType
	 * @throws JsonSupportException JSON解析异常
	 */
	public <T>T parse(String json,Class<T> targetType) throws JsonSupportException{
		if(null == json || 0 == json.length() || json.trim().equals("null")){
			return null;
		}
		if(Date.class.isAssignableFrom(targetType) || Calendar.class.isAssignableFrom(targetType)) {
			return parseDate(json,targetType);
		}
		Class<T> type = Primitives.wrap(targetType);
		if(!Number.class.isAssignableFrom(type) && !Boolean.class.isAssignableFrom(type)) {
			/** 
			 * 目标类型非原始类型且时，如果输入字符串前后没有双引号，也没有[],{}则自动加双引号
			 * 避免解析失败 
			 */
			if(noquote(json, '"', '"') && noquote(json.trim(), '{', '}') && noquote(json.trim(), '[', ']')) {				
				json = "\"" + json + "\"";
			}
		}
		return doParse(json,targetType);
	}
	
	/**
	 * 将字符串解析为日期类型，解析失败抛出异常
	 * @param <D> 日期类型
	 * @param json
	 * @param targetType
	 * @throws JsonSupportException
	 * @since 2.8.8
	 */
	private static <D>D parseDate(String json,Class<D> targetType) throws JsonSupportException {
		json = json.trim();
		/** 前后没有引号 */
		if(noquote(json, '"', '"')) {
			try {
				return TRANSFORMER.cast(Double.valueOf(json).longValue(), Long.class, targetType);
			} catch (NumberFormatException e) {
				D parsed = DateSupport.parseAsDate(json,targetType,new int[0]);
				if(null != parsed) {
					return (D) parsed;
				}
			}
		}else if(quote(json, '"', '"')) {
			return parseDate(json.substring(1, json.length()-1), targetType);
		}
		throw new JsonSupportException("INVALID Date format string: "+json);
	}
	
	/**
	 * input以指定的字符开始和结尾返回{@code true}
	 * @param input
	 * @param left
	 * @param right
	 */
	protected static boolean quote(String input,char left,char right) {
		try {
			return input.charAt(0)==left && input.charAt(input.length()-1)==right;
		} catch (Exception e) {
			return false;
		}
	}
	/**
	 * input不以指定的字符开始和结尾返回{@code true}
	 * @param input
	 * @param left
	 * @param right
	 */
	private static boolean noquote(String input,char left,char right) {
		try {
			return input.charAt(0)!=left && input.charAt(input.length()-1)!=right;
		} catch (Exception e) {
			return true;
		}
	}
}
